﻿using System.Data;
using IMClient.Model.Message;
using Microsoft.Data.Sqlite;

namespace IMClient.Cache.Repositories
{
    public class ChatHistoryRepository
    {
        private readonly SqliteConnection _connection;

        public ChatHistoryRepository()
        {
            var dbContext = DbContext.Instance;
            _connection = dbContext.GetConnection();
        }

        public async Task SaveChatMessageAsync(string userId, ChatMessage chatMessage)
        {
            if (string.IsNullOrWhiteSpace(chatMessage.ReceiverId))
            {
                throw new ArgumentException("ReceiverId cannot be null or empty for ChatMessage.");
            }

            await EnsureConnectionOpenAsync();

            using var command = _connection.CreateCommand();
            command.CommandText = @"
                INSERT INTO chat_history (
                    chat_type, content_type, sender_id, sender_name, sender_avatar, 
                    receiver_id, content, is_read, is_sent_by_user, timestamp
                ) 
                VALUES (
                    @chatType, @contentType, @senderId, @senderName, @senderAvatar, 
                    @receiverId, @content, @isRead, @isSentByUser, @timestamp
                )";

            AddChatMessageParameters(command, chatMessage);
            await command.ExecuteNonQueryAsync();
        }

        public async Task<List<ChatMessage>> GetChatMessagesAsync(string userId, string friendId, int limit = 30, int offset = 0)
        {
            await EnsureConnectionOpenAsync();

            using var command = _connection.CreateCommand();
            command.CommandText = @"
                SELECT chat_type, content_type, sender_id, sender_name, sender_avatar, 
                       receiver_id, content, is_read, is_sent_by_user, timestamp
                FROM chat_history
                WHERE (sender_id = @userId AND receiver_id = @friendId) 
                      OR (receiver_id = @userId AND sender_id = @friendId)
                ORDER BY timestamp ASC
                LIMIT @limit OFFSET @offset";

            command.Parameters.AddWithValue("@userId", userId);
            command.Parameters.AddWithValue("@friendId", friendId);
            command.Parameters.AddWithValue("@limit", limit);
            command.Parameters.AddWithValue("@offset", offset);

            var messages = new List<ChatMessage>();
            using var reader = await command.ExecuteReaderAsync();
            while (await reader.ReadAsync())
            {
                messages.Add(MapToChatMessage(reader));
            }

            return messages;
        }

        public async Task<List<GroupChatMessage>> GetGroupChatMessagesAsync(string userId, string groupId, int limit = 30, int offset = 0)
        {
            await EnsureConnectionOpenAsync();

            using var command = _connection.CreateCommand();
            command.CommandText = @"
                SELECT group_id, group_avatar, chat_type, content_type, sender_id, sender_name, sender_avatar, 
                       content, is_read, timestamp, is_sent_by_user
                FROM group_chat_history
                WHERE user_id = @userId AND group_id = @groupId
                ORDER BY timestamp ASC
                LIMIT @limit OFFSET @offset";

            command.Parameters.AddWithValue("@userId", userId);
            command.Parameters.AddWithValue("@groupId", groupId);
            command.Parameters.AddWithValue("@limit", limit);
            command.Parameters.AddWithValue("@offset", offset);

            var messages = new List<GroupChatMessage>();
            using var reader = await command.ExecuteReaderAsync();
            while (await reader.ReadAsync())
            {
                messages.Add(MapToGroupChatMessage(reader));
            }

            return messages;
        }

        public async Task SaveGroupChatMessageAsync(string userId, GroupChatMessage groupChatMessage)
        {
            if (string.IsNullOrWhiteSpace(groupChatMessage.GroupId))
            {
                throw new ArgumentException("GroupId cannot be null or empty for GroupChatMessage.");
            }

            await EnsureConnectionOpenAsync();

            using var command = _connection.CreateCommand();
            command.CommandText = @"
                INSERT INTO group_chat_history (
                    user_id, group_id, group_avatar, chat_type, content_type, sender_id, sender_name, 
                    sender_avatar, content, is_read, timestamp, is_sent_by_user
                ) 
                VALUES (
                    @userId, @groupId, @groupAvatar, @chatType, @contentType, @senderId, @senderName, 
                    @senderAvatar, @content, @isRead, @timestamp, @isSentByUser
                )";

            command.Parameters.AddWithValue("@userId", userId);
            command.Parameters.AddWithValue("@groupId", groupChatMessage.GroupId);
            command.Parameters.AddWithValue("@groupAvatar", groupChatMessage.GroupAvatar ?? (object)DBNull.Value);
            command.Parameters.AddWithValue("@chatType", groupChatMessage.ChatType);
            command.Parameters.AddWithValue("@contentType", groupChatMessage.ContentType);
            command.Parameters.AddWithValue("@senderId", groupChatMessage.SenderId);
            command.Parameters.AddWithValue("@senderName", groupChatMessage.SenderName);
            command.Parameters.AddWithValue("@senderAvatar", groupChatMessage.SenderAvatar ?? (object)DBNull.Value);
            command.Parameters.AddWithValue("@content", groupChatMessage.Content);
            command.Parameters.AddWithValue("@isRead", groupChatMessage.IsRead ? 1 : 0);
            command.Parameters.AddWithValue("@timestamp", groupChatMessage.Timestamp.ToString("o"));
            command.Parameters.AddWithValue("@isSentByUser", groupChatMessage.IsSentByUser ? 1 : 0);

            await command.ExecuteNonQueryAsync();
        }

        private async Task EnsureConnectionOpenAsync()
        {
            if (_connection.State != ConnectionState.Open)
            {
                await _connection.OpenAsync();
            }
        }

        private static void AddChatMessageParameters(SqliteCommand command, ChatMessage message)
        {
            command.Parameters.AddWithValue("@chatType", message.ChatType);
            command.Parameters.AddWithValue("@contentType", message.ContentType);
            command.Parameters.AddWithValue("@senderId", message.SenderId);
            command.Parameters.AddWithValue("@senderName", message.SenderName);
            command.Parameters.AddWithValue("@senderAvatar", message.SenderAvatar ?? (object)DBNull.Value);
            command.Parameters.AddWithValue("@receiverId", message.ReceiverId);
            command.Parameters.AddWithValue("@content", message.Content);
            command.Parameters.AddWithValue("@isRead", message.IsRead ? 1 : 0);
            command.Parameters.AddWithValue("@isSentByUser", message.IsSentByUser ? 1 : 0);
            command.Parameters.AddWithValue("@timestamp", message.Timestamp.ToString("o"));
        }

        private static ChatMessage MapToChatMessage(SqliteDataReader reader)
        {
            return new ChatMessage
            {
                ChatType = reader.GetString(0),
                ContentType = reader.GetString(1),
                SenderId = reader.GetString(2),
                SenderName = reader.GetString(3),
                SenderAvatar = reader.IsDBNull(4) ? null : reader.GetString(4),
                ReceiverId = reader.GetString(5),
                Content = reader.GetString(6),
                IsRead = reader.GetInt32(7) == 1,
                IsSentByUser = reader.GetInt32(8) == 1,
                Timestamp = DateTime.Parse(reader.GetString(9))
            };
        }

        private static GroupChatMessage MapToGroupChatMessage(SqliteDataReader reader)
        {
            return new GroupChatMessage
            {
                GroupId = reader.GetString(0),
                GroupAvatar = (reader.IsDBNull(1) ? null : reader.GetString(1))!,
                ChatType = reader.GetString(2),
                ContentType = reader.GetString(3),
                SenderId = reader.GetString(4),
                SenderName = reader.GetString(5),
                SenderAvatar = reader.IsDBNull(6) ? null : reader.GetString(6),
                Content = reader.GetString(7),
                IsRead = reader.GetInt32(8) == 1,
                Timestamp = DateTime.Parse(reader.GetString(9)),
                IsSentByUser = reader.GetInt32(10) == 1
            };
        }
    }
}
